import os

import yaml
from configurations.files_path_info import file_paths
from handlers.handler_basics import get_nodes_data, str_to_dict
from handlers.handler_log import logger


class HandlerYaml:
    @classmethod
    def reader_yaml(cls, yaml_file_path: str, *nodes) -> list | tuple | set | dict:
        """
        获取指定yaml文件的节点数据
        :param yaml_file_path: 文件路径
        :return: 文件数据
        """
        try:
            with open(file=yaml_file_path, mode='r', encoding='utf8') as stream:
                # 解析流中的第一个YAML文档, 并生成相应的Python对象。
                yaml_data = yaml.safe_load(stream=stream)
                # 获取yaml 文件中的数据 的指定的节点数据
                result = get_nodes_data(yaml_data, *nodes)
                return result
        except Exception as e:
            logger.exception(f'yaml文件加载异常：{e}')

    def reader_extract_yaml(self, *nodes) -> list | tuple | set | dict:
        """
        获取extract.yaml文件数据 的指定节点数据
        :param nodes: 指定节点
        :return: 指定节点的数据
        """
        try:
            # 将其从二维下降到一维
            nodes = nodes[0]
            # 获取extracts.yaml文件路径
            extracts_file_path = file_paths.get('extracts.yaml')
            # 获取extract.yaml 文件中的数据
            result = self.reader_yaml(extracts_file_path, *nodes)
            return result
        except Exception as e:
            logger.exception(e)

    def reader_testcase_yaml(self, module_name: str, yaml_name: str) -> list | tuple | set | dict:
        """
        获取测试用例yaml的数据
        :param module_name: 模块名，就是存放 用例.yaml 的文件夹名
        :param yaml_name: yaml文件名
        :return: 提起节点的数据
        """
        try:
            yaml_file_path = str(os.path.join(file_paths['testcase'], module_name, yaml_name))
            result = self.reader_yaml(yaml_file_path)
            return result
        except Exception as e:
            logger.exception(f'获取测试用例yaml的数据 异常：{e}')

    def reader_interface_data(self, module_name: str, yaml_name: str) -> dict:
        """
        获取指定测试用例yaml文件的 接口数据
        :param module_name: 模块名
        :param yaml_name: yaml文件名
        :return: 二维数组
        """
        yaml_file_path = str(os.path.join(file_paths['testcase'], module_name, yaml_name))
        try:
            interface_data = self.reader_yaml(yaml_file_path, 0)
            return interface_data
        except Exception as e:
            logger.exception(f'获取指定测试用例yaml文件的 接口数据 异常：{e}')

    def reader_parametrize_data(self, module_name: str, yaml_name: str) -> list:
        """
        获取指定测试用例yaml文件的 parametrize节点数据
        :param module_name: 模块名
        :param yaml_name: yaml文件名
        :return: 二维数组
        """
        try:
            yaml_file_path = str(os.path.join(file_paths['testcase'], module_name, yaml_name))
            parametrize_data = self.reader_yaml(yaml_file_path, 1, 'parametrizes')
            return parametrize_data
        except Exception as e:
            logger.exception(f'获取指定测试用例yaml文件的 parametrize节点数据异常：{e}')

    def reader_parametrize_title_data(self,  module_name: str, yaml_name: str) -> list:
        """
        获取参数化的用例标题
        :param module_name: 模块名
        :param yaml_name: yaml文件名
        :return: 所有参数化用例的标题
        """
        try:
            parametrize_data = self.reader_parametrize_data(module_name, yaml_name)
            title_data = list()
            for data_row in parametrize_data:
                if parametrize_data[0][0] == 'title':
                    title_data.append(data_row[0])
            title_data.remove('title')
            return title_data
        except Exception as e:
            logger.exception(f'获取参数化的用例标题异常：{e}')

    def reader_parametrize_testcase_data(self, module_name: str, yaml_name: str) -> list:
        """
        读取参数化的所有需要发送的用例信息
        :param module_name: 模块名
        :param yaml_name: yaml文件名
        :return: 所有需要发送的用例信息
        """
        try:
            parametrize_data = self.reader_parametrize_data(module_name, yaml_name)
            parametrize_data.remove(parametrize_data[0])
            if isinstance(parametrize_data, list):
                return parametrize_data
        except Exception as e:
            logger.exception(f'读取参数化的所有需要发送的用例信息异常：{e}')

    def reader_parametrize_specific_testcase_data(self, module_name: str, yaml_name: str, index: int) -> list:
        """
        读取参数化的具体需要发送的用例信息
        :param module_name: 模块名
        :param yaml_name: yaml文件名
        :param index: 具体第几个用例信息
        :return: 所有需要发送的用例信息
        """
        try:
            parametrize_data = self.reader_parametrize_testcase_data(module_name, yaml_name)
            return parametrize_data[index - 1]
        except Exception as e:
            logger.exception(f'读取参数化的具体需要发送的用例信息异常：{e}')

    @staticmethod
    def insert_yaml(yaml_url: str, data: dict | str, model='a') -> bool:

        """
        向指定的yaml文件覆盖写入数据
        :param model: 文件写入模式， w 覆盖写入， a 追加写入， 默认为追加写入
        :param yaml_url: 需要写入数据的yaml路径
        :param data: 键值对数据
        :return: false: 插入失败  true： 插入成功
        """
        try:
            # 如果文件不存在就直接生成一个新文件
            if not os.path.exists(yaml_url):
                os.system('echo. > {}'.format(yaml_url))

            # 如果data不是dict类型，将其转换为dict类型
            if isinstance(data, str):
                data = str_to_dict(data)

            # a 模式，追加写入，w模式，覆盖写入
            file = open(file=yaml_url, mode=model, encoding='utf-8')

            # 判断添加的数据格式是否正常
            if isinstance(data, dict):
                # 将data转换成yaml类型的数据，allow_unicode=True表示支持unicode编码，sort_keys=True表示将字典中的键值对的key进行排序。
                yaml_data = yaml.safe_dump(data, allow_unicode=True, sort_keys=True)
                file.write(yaml_data)
                return True
            else:
                return False
        except Exception as e:
            logger.error(f'向指定的yaml文件覆盖写入数据 异常：{e}')

    def insert_extracts_yaml(self, data: dict) -> bool:
        """
        向指定的session.yaml文件插入数据。
        :param data: 字典数据
        :return: false 没有插入成功， true插入成功了
        """
        return self.insert_yaml(file_paths.get('extracts.yaml'), data)

    @staticmethod
    def delete_yaml(yaml_url: str) -> bool:
        """
        清空指定yaml文件中的类容
        :return: false:删除失败  ture：删除成功
        """
        try:
            with open(file=yaml_url, mode='w', encoding='utf-8') as file:
                file.write('')
                return True
        except Exception as e:
            logger.exception(f"{yaml_url}文件清空操作出现未知错误，错误信息为：{e}")
            return False

    def delete_extracts_yaml(self) -> bool:
        """
        清空extracts.yaml文件中的数据
        :return: 是否清空
        """
        return self.delete_yaml(file_paths.get('extracts.yaml'))

    def get_title_position(self, module_name: str, yaml_name: str, title_name: str) -> int | None:
        """
        获取title_name 在参数化数据的位置
        :param title_name: 标题名
        :param module_name:  模块
        :param yaml_name:  用例yaml
        :return: index位置
        """
        parametrize_data = self.reader_parametrize_data(module_name, yaml_name)
        if title_name not in parametrize_data[0]:
            return None
        i = 0
        for data in parametrize_data[0]:
            if data == title_name:
                return i
            i = i + 1
        return i
